#pragma once

#include<iostream>
#include<string>
#include<functional>
#include<sys/select.h>
#include"sock.hpp"

static const int defaultport = 8080;
static const int fdnum = sizeof(fd_set)*8;
static const int defaultfd = -1;

using func_t  = std::function<std::string(const std::string&)>;


class selectServer
{
public:
    selectServer(func_t f,int port = defaultport)
    :_func(f),_port(port),_listensock(-1),_fdarry(nullptr)
    {}

    ~selectServer()
    {
        if(_listensock<0) close(_listensock);
        if(_fdarry) delete[] _fdarry;
    }

    void initServer()
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock,_port);
        Sock::Listen(_listensock);
        _fdarry = new int[fdnum];
        for(int i=0;i<fdnum;i++) _fdarry[i] = defaultfd;
        _fdarry[0] = _listensock;
    }

    void Print()
    {
        std::cout<<"fd list ";
        for(int i=0;i<fdnum;i++)
        {
            if(_fdarry[i] != defaultfd)
                std::cout<<_fdarry[i]<<" ";
        }
        std::cout<<std::endl;
    }

    void Accepter(int listensock)
    {
        logMessage(DEBUG,"Accepter in");
        std::string clientip;
        uint16_t clientport = 0;
        int sock = Sock::Accept(listensock,&clientip,clientport);
        if(sock<0) return;
        logMessage(NORMAL,"accept success [%s:%d]",clientip.c_str(),clientport);

        //需要将sock托管给select
        int i=0;
        for(i;i<fdnum;i++)
        {
            if(_fdarry[i]!=defaultfd) continue;
            else break;
        }

        if(i==fdnum)
        {
            logMessage(WARNING,"server if full,please wait");
            close(sock);
        }
        else
            _fdarry[i] = sock;
        Print();
        logMessage(DEBUG,"Acceptr out");
    }

    void Recver(int sock,int pos)
    {
        logMessage(DEBUG,"in Recver");

        //1.读取request
        //如果一次性不能把数据读完，则会有bug
        char buffer[1024];
        ssize_t s = recv(sock,buffer,sizeof(buffer)-1,0);
        if(s>0)
        {
            buffer[s] = 0;
            logMessage(NORMAL,"client# %s",buffer);
        }
        else if(s==0)
        {
            close(sock);
            _fdarry[pos] = defaultfd;
            logMessage(NORMAL,"client quit");
            return;
        }
        else
        {
            close(sock);
            _fdarry[pos] = defaultfd;
            logMessage(ERROR, "client quit: %s", strerror(errno));
            return;
        }

        //2.处理resquest
        std::string response = _func(buffer);

        //3.返回response
        write(sock,response.c_str(),response.size());

        logMessage(DEBUG,"out Recver");
    }

    void HandlerReadEvent(fd_set &rfds)
        {
            for (int i = 0; i < fdnum; i++)
            {
                // 过滤掉非法的fd
                if (_fdarry[i] == defaultfd)
                    continue;

                // 正常的fd
                // 正常的fd不一定就绪了
                // 目前一定是listensock，只有这一个
                if (FD_ISSET(_fdarry[i], &rfds) && _fdarry[i] == _listensock)
                    Accepter(_listensock);
                else if(FD_ISSET(_fdarry[i], &rfds))
                    Recver(_fdarry[i], i);
                else{}
            }
        }


    void start()
    {
        while(true)
        {
            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd = _fdarry[0];

            for(int i=0;i<fdnum;i++)
            {
                if(_fdarry[i]==defaultfd) continue;
                FD_SET(_fdarry[i],&rfds);

                if(maxfd<_fdarry[i]) maxfd = _fdarry[i];
            }
            logMessage(NORMAL,"max fd is %d",maxfd);

            //要注意理解select的执行过程，以及中间三个参数是输入输出型参数
            int n = select(maxfd+1,&rfds,nullptr,nullptr,nullptr);
            switch(n)
            {
            case 0:
                logMessage(NORMAL,"time out");
                break;
            case -1:
                logMessage(WARNING,"select error, code: %d, err string: %s", errno, strerror(errno));
                break;
            default:
                logMessage(NORMAL,"have event ready!");
                HandlerReadEvent(rfds);
                break;
            }
        }
    }

private:
    int _port;
    int _listensock;
    int *_fdarry;
    func_t _func;
};
